
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <math.h>
#include <signal.h>
#include <string.h>
#include "Portdef.h"
#include "Cpci7841.h"
#include "Api7841.h"
#include <time.h>
#include <taskLib.h>

#define LED_ADDR_START		(64)

typedef struct
{
	unsigned short    	initFlag;
	unsigned char   	ownerSet;
	int  				deviceID;
	struct sigaction 	sigAct1, sigAct2; 
}Lib_PCI_Info;

int	g_TotalCards = 0;

BYTE g_LedStatus[MAXSUPPORT];
BYTE g_CanIntStatus[MAXSUPPORT*2];
PORT_STRUCT g_PortStruct[MAXSUPPORT*2];
Lib_PCI_Info g_PciInfo7841[MAXSUPPORT];

int InstallRef[MAXSUPPORT*2] = { 0, 0, 0, 0, 0, 0, 0, 0};

void Nsleep(unsigned long ns)
{
	struct timespec tm;
	
	tm.tv_sec = 0;
	tm.tv_nsec = ns;
	
	nanosleep(&tm, NULL);
}

int InstallCpci7841(int cardNo)
{
	int devId;
	
	if (cardNo >= MAXSUPPORT)
	{
		return ERR_INVALIDCARDNUMBER;
	}
	
    if((devId = OpenCpci7841(cardNo)) < 0)
    {
    	return ERR_OPENFILEFAILED;
    }

    memset(&(g_PciInfo7841[cardNo]), 0, sizeof(Lib_PCI_Info));
    
    g_PciInfo7841[cardNo].deviceID = devId;
    g_PciInfo7841[cardNo].initFlag = 0x7841;
    
    return(ERR_NOERROR);
}

int	CanGetReceiveEvent(int handle, void (*event_handler)(int))
{
	int retValue = 0;
	U16 enableFlag = TRUE;
	
	if(g_PciInfo7841[handle / 2].initFlag == FALSE)
	{
		return ERR_BOARDNOINIT;	
	}
    
	if (InstallRef[handle] != 0) 
	{
		if(g_PciInfo7841[handle / 2].ownerSet == 0)
		{
			return ERR_OWNERSET; // check the owner setting	
		}
		
		if(event_handler == NULL)
		{
			return (ERR_SIGNALHANDLE);	
		}
		else
		{
			if ((handle % 2) == 0)
			{
				g_PciInfo7841[handle/2].sigAct1.sa_handler = event_handler;
				g_PciInfo7841[handle/2].sigAct1.sa_flags |= SA_RESTART;
				
				if(sigaction(SIGEVENT1, &(g_PciInfo7841[handle/2].sigAct1), NULL) == -1)
				{
					return(ERR_SIGNALNOTIFY);	
				}
				
				retValue = Can7841Ioctl(g_PciInfo7841[handle/2].deviceID,IOCTL_7841_SIGNAL1_SET,(unsigned long)&(enableFlag));
			}
			else 
			{
				g_PciInfo7841[handle/2].sigAct2.sa_handler = event_handler;
				g_PciInfo7841[handle/2].sigAct2.sa_flags |= SA_RESTART;
				
				if(sigaction(SIGEVENT2, &(g_PciInfo7841[handle/2].sigAct2), NULL) == -1)
				{
					return(ERR_SIGNALNOTIFY);
				}
				
				retValue = Can7841Ioctl(g_PciInfo7841[handle/2].deviceID,IOCTL_7841_SIGNAL2_SET,(unsigned long)&(enableFlag));
			}
			if( retValue == 0 )
			{
				return(ERR_NOERROR);
			}
			else
			{
				return (ERR_ALLOCATEMEMORY);	
			}
		}
	}
	else
	{
		return ERR_BOARDNOINIT;	
	}
}

int	CanStopReceiveEvent(int handle)
{
	int retValue = 0;
	U16 enableFlag = FALSE;
	
	if(g_PciInfo7841[handle / 2].initFlag == FALSE)
	{
		return ERR_BOARDNOINIT;
	}
	
	if (InstallRef[handle] != 0 ) 
	{
		if ((handle % 2) == 0)
		{
			retValue = Can7841Ioctl(g_PciInfo7841[handle / 2].deviceID, IOCTL_7841_SIGNAL1_SET, (unsigned long)&enableFlag);
			g_PciInfo7841[handle/2].sigAct1.sa_handler = SIG_IGN;
			if(sigaction(SIGEVENT1, &(g_PciInfo7841[handle/2].sigAct1), NULL ) == -1)
			{
				return(ERR_SIGNALNOTIFY);	
			}
		}
		if ((handle % 2) == 1)
		{
			retValue = Can7841Ioctl(g_PciInfo7841[handle/2].deviceID, IOCTL_7841_SIGNAL2_SET, (unsigned long)&enableFlag);
			g_PciInfo7841[handle/2].sigAct2.sa_handler = SIG_IGN;
			if(sigaction(SIGEVENT2, &(g_PciInfo7841[handle/2].sigAct2), NULL ) == -1)
			{
				return(ERR_SIGNALNOTIFY);	
			}
		}
		if(retValue == 0)
		{
			return(ERR_NOERROR);	
		}
		else
		{
			return (ERR_ALLOCATEMEMORY);	
		}
	}
	else
	{
		return ERR_BOARDNOINIT;	
	}
}

int	CanOpenDriver(int cardNo, int port)
{
	int index = 0;
	PORT_STRUCT setPort; //for init config
	
	if(g_PciInfo7841[cardNo].initFlag == FALSE)
	{
		if (InstallCpci7841(cardNo) != ERR_NOERROR)
		{
			return -1;
		}
		else
		{
			g_TotalCards++;	
		}
	} 
	
	index = cardNo * 2 + port;
	InstallRef[index] = 1;
	
	//init config
	setPort.mode = 0;       	//  0 : 11-bit ;  1 : 29-bit CAN network
	setPort.accCode = 0;       	//  Only ID = accCode can pass the filter
	setPort.accMask = 0x7ff;   	//  Don't care bit
	setPort.baudrate = 2;       //  0: 125kBps; 1:250kBps;  2:500kBps; 3:1MBps
	CanConfigPort(index, &setPort);
	
	return index;    	
}

void ConfigCanPort(int handle, int baudrate)
{
	PORT_STRUCT setPort; //for init config
	
	//init config
	setPort.mode = 0;       	     //  0 : 11-bit ;  1 : 29-bit CAN network
	setPort.accCode = 0;       	     //  Only ID = accCode can pass the filter
	setPort.accMask = 0x7ff;   	     //  Don't care bit
	setPort.baudrate = baudrate;     //  0: 125kBps; 1:250kBps;  2:500kBps; 3:1MBps
	CanConfigPort(handle, &setPort);
}

int CanCloseDriver(int handle)
{
	int anotherPort, count;
	REG_RW tempWriteReg;
	
	if (InstallRef[handle] != 1)
	{
		return -1;	
	}
	
	InstallRef[handle] = 0;
	tempWriteReg.offset = (handle % 2) * 128;
	tempWriteReg.data = 0x01;
	Can7841Ioctl(g_PciInfo7841[handle / 2].deviceID, IOCTL_7841_CLOSE_PORT, (unsigned long)&tempWriteReg);
	anotherPort = 0;
	
	for(count = 0; count < g_TotalCards * 2; count++)
	{
		if (InstallRef[count] == 1)
		{
			anotherPort = 1;	
		}		
	}

	if (anotherPort == 0)
	{
		tempWriteReg.offset = LED_ADDR_START;
		tempWriteReg.data = 0xFF;
		Can7841Ioctl(g_PciInfo7841[handle / 2].deviceID, IOCTL_7841_CLOSE_CARD, (unsigned long)&tempWriteReg);
	}
	
	return 0;
}

int	CanConfigPort(int handle, PORT_STRUCT *portStruct)
{
	int i;
	BYTE temp;
	RETINFO retInfo;
	
	// Port has not installed
	if (InstallRef[handle] != 1)
	{
		return -1;		
	}

	if (portStruct == NULL)
	{
		return -1;	
	}

	if ((portStruct->mode != 0) && (portStruct->mode != 1))
	{
		return -1;	
	}
	
	//Disable Interrupt
	Write7841(handle, 4, 0x00); //4:Interrupt enable register address
	
	//Entering Reset mode
	temp = Read7841(handle, 0);// 0:reset mode register address
	Nsleep(10000); //10us

	for(i = 0; i < 100; i++)
	{
		if(temp & 0x01)
		{
			break;
		}
		
		Write7841(handle, 0, 0x01); // reset operator
		Nsleep(10000); //10us
		temp = Read7841(handle, 0); 
	}
	
	//setup PeliCAN, CBP=1, No TX1 output and No Clk out
	Write7841(handle, 31, 0xC8); //31: clk division register.BIT3 = 1,close clk;BIT6 =cBP =1, only RX0 activated;BIT7 = 1,PeliCan selected.
	
	//setup acceptance code & acceptance mask,Standard frame, single filter mode
	if(portStruct->mode == 0)//11-bit ID
	{
		//Disable checking data field
		Write7841(handle, 18, 0x00);
		Write7841(handle, 19, 0x00);
		Write7841(handle, 22, 0xff);
		Write7841(handle, 23, 0xff);
		
		Write7841(handle, 16, (BYTE)(portStruct->accCode >> 3));
		Write7841(handle, 17, (BYTE)((portStruct->accCode << 5) | 0x10));
		Write7841(handle, 20, (BYTE)(portStruct->accMask >> 3));
		Write7841(handle, 21, (BYTE)((portStruct->accMask << 5) | 0x10));
	}
	else//	29-bit ID
	{
		//Fill Acceptance Code Register
		Write7841(handle, 16, (BYTE)(portStruct->accCode >> 21));
		Write7841(handle, 17, (BYTE)(portStruct->accCode >> 13));
		Write7841(handle, 18, (BYTE)(portStruct->accCode >> 5));
		Write7841(handle, 19, (BYTE)(portStruct->accCode << 3));
		
		//Fill Acceptance Mask Register
		Write7841(handle, 20, (BYTE)(portStruct->accMask >> 21));
		Write7841(handle, 21, (BYTE)(portStruct->accMask >> 13));
		Write7841(handle, 22, (BYTE)(portStruct->accMask >> 5));
		Write7841(handle, 23, (BYTE)(portStruct->accMask << 3) | 0x04);  // Or RTR
	}
	
	//setup bus timing registers
	switch(portStruct->baudrate)
	{
		//125kBps
		case 0:	
			Write7841(handle, 6, 0x03);
			Write7841(handle, 7, 0x1C);
			break;
		//250kBps
		case 1:	
			Write7841(handle, 6, 0x01);
			Write7841(handle, 7, 0x1C);
			break;
		//500kBps
		case 2:	
			Write7841(handle, 6, 0x00);
			Write7841(handle, 7, 0x1C);
			break;
		//1MkBps
		case 3:	
			Write7841(handle, 6, 0x00);
			Write7841(handle, 7, 0x14);
			break;
		//Self Defined Baudrate
		case 4: 
			Write7841(handle, 6, portStruct->brp | portStruct->sjw << 6);
			// 2007/04/25 Bug fix!
			Write7841(handle, 7, portStruct->sam << 7 | portStruct->tseg2 << 4 | portStruct->tseg1);
			break;
		
		default:
			return -1;
	}
	
	//setup output control register;  normal mode; push-pull
	Write7841(handle, 8, 0xfa);
	
	//return operation mode,write port mode to VXD
	retInfo.handle = handle;
	retInfo.mode = portStruct->mode;
	Can7841Ioctl(g_PciInfo7841[handle/2].deviceID, IOCTL_7841_SET_PORT_MODE, (unsigned long)&retInfo);
	
	//enable receive interrupt
	Write7841(handle, 0, 0x08);
	Write7841(handle, 4, 0xFD);
	
	//copy configuration to Port Setting
	memcpy((void*)(&(g_PortStruct[handle])), portStruct, sizeof(PORT_STRUCT));
	
	return 0;
}

int	CanGetPortStatus(int handle, PORT_STATUS *portStatus)
{
	memcpy((void*)&(portStatus->port), (void*)(&(g_PortStruct[handle])), sizeof(PORT_STRUCT));
	(portStatus->status).reg = Read7841(handle, 2);
	
	return 0;
}

BYTE Read7841(int handle, int offset)
{
	REG_RW tempReg;
	
	if (InstallRef[handle] == 0)
	{
		return 0;
	}
	
	tempReg.offset = offset + (128 * (handle % 2));
	Can7841Ioctl(g_PciInfo7841[handle / 2].deviceID, IOCTL_7841_REG_READ, (unsigned long)&tempReg);
	
	return (tempReg.data);
}

void Write7841(int handle, int offset, BYTE data)
{ 
    REG_RW tempReg;

    if (InstallRef[handle] == 0)
    {
    	return;    	
    }

    tempReg.offset = offset + (128 * (handle % 2));
    tempReg.data = data;
    Can7841Ioctl(g_PciInfo7841[handle / 2].deviceID, IOCTL_7841_REG_WRITE, (unsigned long)&tempReg);
}


BYTE CanGetLedStatus(int cardNo, int index)
{
	return (g_LedStatus[cardNo]>>index) & 1;
}

void CanSetLedStatus(int cardno, int index, int mode)
{
	BYTE tmp;
    REG_RW tempWriteReg;

    tmp = 0x01 << index;
    switch(mode)
    {
        case 0 : g_LedStatus[cardno] &= ~tmp;                
                 break;
                 
        case 1 : g_LedStatus[cardno] |= tmp;
                 break;
                 
        case 2 : break;
    }

    tempWriteReg.offset = LED_ADDR_START;
    tempWriteReg.data = g_LedStatus[cardno];
    Can7841Ioctl(g_PciInfo7841[cardno].deviceID, IOCTL_7841_REG_WRITE, (unsigned long)&tempWriteReg);
	
    return;
}

void  CanEnableReceive(int handle)
{
	Write7841(handle, 4, Read7841(handle, 4) | 0x01);
	
	return;
}


void  CanDisableReceive(int handle)
{
	Write7841(handle, 4, Read7841(handle, 4) & 0xFE);
	
	return;
}

int CanSendMsg(int handle, CAN_PACKET *msg)
{
	CAN_MSG canMsg;
	long   result, i;
	PORT_STATUS status;
	
	//Retry 100 times until TX transmittion was done
	for( i = 0; i < 100; i++)
	{
		CanGetPortStatus(handle, &status);
		if(status.status.bit.txBuffer == 0)
		{
			Nsleep(10000); //10us
		}
		else
		{
			break;
		}
	}
	
	if(i == 100)
	{
		CanConfigPort(handle, &g_PortStruct[handle]);
	}
	
	memcpy((CAN_PACKET*)(&(canMsg.msg)), msg, sizeof(CAN_PACKET));
	
	canMsg.handle = handle;
	Can7841Ioctl(g_PciInfo7841[handle/2].deviceID, IOCTL_7841_SET_BUFFER_DATA, (unsigned long)&canMsg);
	
	//yuan modify 06/18/01
	result = canMsg.retVal;
	if (result < 0)
	{
		return -1;	
	}
	
	return 0;
}

int CanRcvMsg(int handle, CAN_PACKET *msg)
{
	long   result; 
	CAN_MSG	canMsg;
	
	if((msg == NULL) || (InstallRef[handle] != 1))
	{
		return -1;	
	}	
	
	canMsg.handle = handle;	
	Can7841Ioctl(g_PciInfo7841[handle/2].deviceID, IOCTL_7841_GET_BUFFER_DATA, (unsigned long)&canMsg);
	
	//yuan modify 06/18/01
	result = canMsg.retVal;
	if (result >= 0) 
	{//yuan modify for data received successfully 
		memcpy(msg, (CAN_PACKET*)(&(canMsg.msg)), sizeof(CAN_PACKET));
		return 0;
	}
	return -1;
}

int CanGetRcvCnt(int handle)
{
	REC_CN	recCn;
	
	if(InstallRef[handle] != 1)
	{
		return -1;
	}

	recCn.handle = handle;	
	Can7841Ioctl(g_PciInfo7841[handle/2].deviceID, IOCTL_7841_GET_UNRD_COUNT, (unsigned long)&recCn);
	
	return recCn.retVal;
}

void  CanClearOverrun(int handle)
{
	//Clear Data Overrun
	Write7841(handle, 1, 0x08);
	
	//Enable Data Overrun Interrupt and Receive Interrupt
	Write7841(handle, 4, Read7841(handle, 4) | 0x09);
}

void  CanClearRxBuffer(int handle)
{
	int i;
	
	if(InstallRef[handle] != 1)
	{
		return ;
	}

	// 2008/06/03 - Bug fixed. Clear hardware buffers in limited number
	for(i = 0; i < 64; i++) //RXFIFO have 64 bytes
	{
		if(Read7841(handle, 29) != 0) //29:rx information counter. reflect RXFIFO number of usable information
		{
			Write7841(handle, 1, 0x04); //1:command register.04:expression release reception buffer
		}
		else
		{
			break;
		}
	}
	
	//2008/06/03 - Clear driver buffers
	Can7841Ioctl(g_PciInfo7841[handle/2].deviceID, IOCTL_7841_CLEAR_RX_BUFFER, (unsigned long)&handle);
	
	return;
}

void CanClearTxBuffer(int handle)
{
	if(InstallRef[handle] != 1)
	{
		return ;	
	}

	//write SJA CMR to abort transmission
	Write7841(handle, 1, 0x02); //2:express abort send
	
	//2008/06/03 - Clear driver buffers
	Can7841Ioctl(g_PciInfo7841[handle / 2].deviceID, IOCTL_7841_CLEAR_TX_BUFFER, (unsigned long)&handle);
	
	return;
}

BYTE CanGetArbitrationLostBit(int handle)
{
    return Read7841(handle, 11);
}

BYTE CanGetErrorCode(int handle)
{
    return Read7841(handle, 12);
}

BYTE CanGetErrorWarningLimit(int handle)
{
	return Read7841(handle, 13);
}

void CanSetErrorWarningLimit(int handle, BYTE limit)
{
	BYTE v = Read7841(handle, 0);
	
	//enter RESET mode
	Write7841(handle, 0, 1);
	Write7841(handle, 13, limit);
	Write7841(handle, 0, v);
}

BYTE CanGetRxErrorCount(int handle)
{
    return Read7841(handle, 14);
}

BYTE CanGetTxErrorCount(int handle)
{
    return Read7841(handle, 15);
}

void CanSetTxErrorCount(int handle, BYTE value)
{
	BYTE v = Read7841(handle, 0);
	
	//enter RESET mode
	Write7841(handle, 0, 1);
	Write7841(handle, 15, value);
	Write7841(handle, 0, v);
}

BYTE CanGetIntStatusReg(int handle)
{
	return g_CanIntStatus[handle];
}

int CanDetectBaudrate(int handle, int miliSecs)
{
	time_t start,end;
	BYTE previousMode;
	PORT_STRUCT save, set;
	long count, mode = -1;

	//Save previous Port setting
	memcpy((void*)&save, (void*)&g_PortStruct[handle], sizeof(PORT_STRUCT));
	memcpy((void*)&set, (void*)&save, sizeof(PORT_STRUCT));
	
	//Bit-rate detection algorithm,save previoius mode and enter Listen only mode
	previousMode = Read7841(handle, 0);
	Write7841(handle, 0, 0x02);
	
	for(count = 3;count >= 0;count--)
	{
		set.baudrate = count;
		CanConfigPort(handle, &set);
		g_CanIntStatus[handle] = Read7841(handle,0x02);
		g_CanIntStatus[handle] &= 0xFE;
		Write7841(handle,0x02,g_CanIntStatus[handle]);
		CanEnableReceive(handle);
		time(&start);
		
		do
		{
			g_CanIntStatus[handle] = Read7841(handle,0x02);
			// Bus error occurs
			if(g_CanIntStatus[handle] & 0x80)
			{
				break;
			}
			if(g_CanIntStatus[handle] & 0x01)
			{
				mode = count;
				break;
			}
			
			time(&end);
		} while(difftime(end,start)<((double)miliSecs/1000.0));
		
		if (mode != -1)
		{
			break;
		}
	}
	
	CanConfigPort(handle, &save);
	CanEnableReceive(handle);
	Write7841(handle, 0, previousMode);
	
	if (mode == -1)
	{
		return -1;
	}
	
	return mode;
}
